package info.qingshui.browser.hk.setting;


import info.qingshui.browser.hk.HKWebViewClient;
import info.qingshui.browser.hk.db.ObjectDB;



import info.qingshui.browser.hk.file.FileHelper;
import info.qingshui.browser.hk.file.FileManager;
import info.qingshui.browser.hk.index.URLInfo;
import info.qingshui.browser.util.Pair;


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.TreeMap;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;

import android.view.View;
import android.webkit.*;
import android.webkit.WebSettings.LayoutAlgorithm;
import android.webkit.WebSettings.RenderPriority;

public class Setting implements Serializable{
	public static String UA_TAIL = "qingshui";
	
	//代理服务器相关
//	private int   localPort = 18080;
//	private String proxyHost = "112.121.189.69";
//	private int proxyPort = 53;
//	private String username = "qingshui";
//	private String password = "qingshui";

	private static final long serialVersionUID = 1L;
	private static Setting setting = null;//单一模式
	public static final int VERSION = 6;//当前程序的配置版本
	
	public static final String GA_UA = "UA-31429755-1";
	
	public static final String USE_PROXY_KEY = "use_proxy_setting";
	public static final String FONT_KEY = "font_setting";
	public static final String FONT_NORMAL = "normal";
	public static final String FONT_BIG = "big";
	public static final String FONT_LARGE = "large";
	
	
	public static final String SETTING_PATH = "setting/" + VERSION;//配置文件保存在私有空间和assets下setting目录下,assets保留默认配置
	public static final String SETTING_START = "<!--#############";//合法的文件第一行开头13#开头,第一行不一样说明需要更新配置
	
	public static final ConfigServer DEFAULT_UPDATE_Server = new ConfigServer("c.12315bbs.com","80");
	
	public static final String SETTING_CONFIGS_FILENAME = "configs.txt";//配置服务器列表服务器列表配置文件名
	public static final String SETTING_VHOSTS_FILENAME = "vhosts.txt";//虚拟主机配置文件名
	public static final String SETTING_CONFIGSERVERS_FILENAME = "configServers.txt";
	public static final String SETTING_URLS_FILENAME = "urls.txt";
	public static final String SETTING_INDEX_FILENAME = "index.html";//首页配置文件名
	public static final String SETTING_ERROR_FILENAME = "error.html";//首页配置文件名
	
	public static final String DEFAULT_INDEX_URL = "file:///android_asset/"+ SETTING_PATH + "/"+ SETTING_INDEX_FILENAME;
	public static final String ERROR_PAGE =  "file:///android_asset/" + SETTING_PATH + "/" + SETTING_ERROR_FILENAME;

	
	private transient Context ctx;
	private transient boolean modified;//是否需要保存，如果有修改部分设置信息true
	private transient boolean isRemaindedUpdate;//是否已经提示升级

	private transient Map<String,VHostInfo> vhosts = null;//经过虚拟主机的原域名和需要代理域名对应关系
	//可更新配置文件的服务器http://xx.xx.com/ 格式
	private transient Pair<String ,Queue<ConfigServer>> configServers = null;//更新配置的地址列表
	
	private transient Pair<String ,Map<String,URLInfo>> chinaURLs = null;//大陆网址
	private transient Pair<String , Map<String,URLInfo>> hongkongURLs = null;//香港网址
	private transient Pair<String, Map<String,URLInfo>> taiwanURLs = null;//台湾网址
	private transient Pair<String, Map<String,URLInfo>> haiwaiURLs = null;//海外网址
	private transient Pair<String, Map<String,URLInfo>> othersURLs = null;//其他网址
	
	//配置文件格式:文件名		更新地址		文件类型
	private Pair<String ,Map<String, UpdateFileInfo>> configs = null; //需要更新的文件列表
	private long startTime;//本次程序启动时间
	private boolean isFirstTimeUpdateConfig;//是否第一次
	//private boolean isNeedUpdateVersion = false;//是否需要升级
	private String updateName ;//要升级的文件名
	private String updateType ;//升级类型
	private String updateVersionUrl = "";
	private String updateDesc = "";//升级提示内容
	
	private long userId = 0;//用户标识
	private int loginTimes = 0;//登录次数
	
	
	private transient String defaultUserAgent = "";
	private transient boolean networkOK;//是否网络已经可用
	
	/**
	 * 是否是老用户，老用户给更多的权限
	 * @return
	 */
	public boolean isOldUser() {
		if ( loginTimes >= 30 ) {
			return true;
		} else {
			return false;
		}
	}
	
	public boolean isNetworkOK() {
		return networkOK;
	}

	public void setNetworkOK(boolean networkOK) {
		this.networkOK = networkOK;
	}

	public String toString() {
		return "configServers=" + configServers
		+ ";configs=" +configs
		+ ";startTime=" +startTime
		+ ";isFirstTimeUpdateConfig=" +isFirstTimeUpdateConfig
		+ ";chinaURLs=" +chinaURLs
		+ ";hongkongURLs=" +hongkongURLs
		+ ";taiwanURLs=" +taiwanURLs
		+ ";vhosts=" +vhosts;
	}
	
	//加载当前最低要求必须配置信息
	public void loadSetting() {
		loadConfigServersSetting();
		loadConfigsSetting();
		loadVhostsSetting();
		loadURLs();
		this.saveSettingIfNeeded();
	}

	/**
	 * 设置当前时间为启动时间
	 */
	public void setStartTimeNow() {
		this.startTime = System.currentTimeMillis();
		this.modified = true;
	}
	
	/**
	 * 上次运行是否在今天之内,主要用于判断需要一天运行一次的任务
	 * @return
	 */
	public boolean isStartToday() {
		return ( (System.currentTimeMillis() - startTime) <= 1000*3600*24 );
	}
	
	private Setting(Context ctx) {
		this.ctx = ctx;
		modified = false;
		isFirstTimeUpdateConfig = true;
		
		 genUserId();
		loadSetting();//读取相关配置文件保存配置
		
		//vhosts = new HashMap<String,String>();
	}
	
	private void genUserId() {//没有生成时生成
		if( userId == 0 ) {
			userId = System.currentTimeMillis();
			modified = true;
		}
	}
	
	
	public synchronized static Setting getSetting( Context ctx ) {
		
		if ( setting == null ) {
			//从数据库load回数据
			Setting s = (Setting)ObjectDB.getObjectDB(ctx).getObject( Setting.class.getName() );
			if ( s != null ) {
				s.ctx = ctx;
				
				s.loadSetting();
				s.genUserId();
				setting =s;
				
			} else {
				setting = new Setting( ctx );
			}
			Log.d(Setting.class.getSimpleName(), "getSetting:" + setting);
		}
		return setting;
	}
	
	
	/**
	 * 检查是否需要保存，并后台保存，在异步任务来执行这个接口
	 */
	public void saveSettingIfNeeded() {
		if( modified ) {
			ObjectDB.getObjectDB(ctx).saveObject(this);
			modified = false;
			Log.d(Setting.class.getSimpleName(), "saveSettingIfNeeded" );
		}
	}

	public Context getCtx() {
		return ctx;
	}

	
	public void setWebViewDefaultSettings(WebView webView) {
		// 设置WebView属性
		webView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);
		webView.getSettings().setJavaScriptEnabled(true);// 能够执行Javascript脚本
		webView.getSettings().setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS);

		webView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);
		webView.getSettings().setAppCacheMaxSize(1024 * 1024 * 20);// 20M
		//支持缩放
		webView.getSettings().setSupportZoom(true);
		// 缩放按钮
		webView.getSettings().setBuiltInZoomControls(true);
		
		webView.getSettings().setBlockNetworkImage(false);
		webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(false);
		//支持缩略图
		webView.getSettings().setUseWideViewPort(true);
		
		//webView.getSettings().setNeedInitialFocus(true);
		webView.getSettings().setLoadWithOverviewMode(true);
		webView.getSettings().setRenderPriority(RenderPriority.HIGH);//加快渲染速度
		webView.getSettings().setPluginsEnabled(true);
		webView.getSettings().setDefaultZoom(WebSettings.ZoomDensity.MEDIUM) ;//双击放大的大小
		
		webView.getSettings().setDatabaseEnabled(true);
		webView.getSettings().setDomStorageEnabled(true);
		webView.getSettings().setGeolocationEnabled(true);
		
		//webView.clearSslPreferences();
		//webView.getSettings().sewebView.getSettings().set
		
		String ua = webView.getSettings().getUserAgentString();
		if( "".equals( defaultUserAgent ) || null == defaultUserAgent ) {
			this.defaultUserAgent = ua;
		}
		if( ua !=null && !ua.endsWith(UA_TAIL) ) {
			webView.getSettings().setUserAgentString( this.defaultUserAgent + " " + UA_TAIL );
		}
		
//		if ( this.isUseProxy() ) {
//			ProxySettings2.resetProxy( this.ctx );
//		}
		
		String fontSize = this.getFontSize();
		if ( fontSize.equals(Setting.FONT_BIG)) {
			webView.getSettings().setTextSize(android.webkit.WebSettings.TextSize.LARGER);
		} else if  ( fontSize.equals(Setting.FONT_LARGE)) {
			webView.getSettings().setTextSize(android.webkit.WebSettings.TextSize.LARGEST);
		} else {
			webView.getSettings().setTextSize(android.webkit.WebSettings.TextSize.NORMAL);
		}
	}
	
	
	private void loadVhostsSetting() {
		HashMap<String,VHostInfo> temp = new HashMap<String,VHostInfo>();
		try {
			String line =null;
			String versionLine ;
			BufferedReader isr = getNewBufferedReader(Setting.SETTING_VHOSTS_FILENAME);
			if ( isr == null ) {
				isr = this.getDefaultBufferedReader( Setting.SETTING_VHOSTS_FILENAME );
				versionLine = isr.readLine();
			} else {
				versionLine = isr.readLine();
				if ( versionLine == null  || versionLine.indexOf( Setting.SETTING_START ) < 0) {
					isr = this.getDefaultBufferedReader( Setting.SETTING_VHOSTS_FILENAME );
					versionLine = isr.readLine();
				}
			}
			
			if ( this.vhosts != null && this.vhosts.get( versionLine ) != null ) {
				return;
			}
			
			temp.put(versionLine, new VHostInfo() );
			while (  (line=isr.readLine()) != null ) {
				String[] ss = line.split("\\t");
				if ( ss.length >= 3) {
					try {
						VHostInfo vHostInfo = new VHostInfo();
						vHostInfo.setHost( ss[0] );
						vHostInfo.setProxyServers( ss[1] );
						vHostInfo.setUa( ss[2] );
						temp.put(ss[0], vHostInfo);//host ,id/port
					}catch(Exception e) {
						//ignore
					}
				}
			}
			this.vhosts = temp;
			Log.d(Setting.class.getSimpleName(), "loadVhostsSetting return:" + this.vhosts);
		} catch (Exception e) {
			this.vhosts = temp;
			Log.w(Setting.class.getSimpleName(), "loadVhostsSetting 失败" ,e);
		} 
		
		
	}
	
	public boolean loadConfigsSetting() {
		HashMap<String,UpdateFileInfo> temp = new HashMap<String,UpdateFileInfo>();
		try {
			String line =null;
			String versionLine ;
			BufferedReader isr = getNewBufferedReader(Setting.SETTING_CONFIGS_FILENAME);
			if ( isr == null ) {
				isr = this.getDefaultBufferedReader( Setting.SETTING_CONFIGS_FILENAME );
				versionLine = isr.readLine();
			} else {
				versionLine = isr.readLine();
				if ( versionLine == null  || versionLine.indexOf( Setting.SETTING_START ) < 0) {
					isr = this.getDefaultBufferedReader( Setting.SETTING_CONFIGS_FILENAME );
					versionLine = isr.readLine();
				}
			}
			
			if ( this.configs != null && configs.first.equals( versionLine )  ) {
				//已经载入过
				return false;
			}
//文件格式
//文件名		更新的URL	文件类型		文件备注说明
			while (   (line=isr.readLine()) != null ) {
				String[] ss = line.split("\\t");
				if ( ss.length >= 3) {
					//如果文件名是以hk-v开头的，则是需要升级的配置文件
					if( ss[0].startsWith("hk-v") ) {
						//Log.i(Setting.class.getSimpleName(), "loadConfigsSetting found  update file :hk-v" );
						try {
							this.updateName = ss[0];
							this.updateVersionUrl = ss[1];
							this.modified = true;
							if( ss.length >= 4 ) {
								this.updateDesc = ss[3].replaceAll("<br/>", "\n");
							}
							this.isRemaindedUpdate = false;
						} catch (Throwable e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					} else {
						UpdateFileInfo updateFileInfo = new UpdateFileInfo();
						updateFileInfo.setFileName( ss[0] );
						updateFileInfo.setUpdateURL(ss[1] );
						updateFileInfo.setType( ss[2] );
						temp.put(ss[0], updateFileInfo);
					}
				}
			}
			this.configs = new Pair<String ,Map<String, UpdateFileInfo>> (versionLine, temp);
			this.modified = true;
			this.saveSettingIfNeeded();
			Log.i(Setting.class.getSimpleName(), "loadConfigsSetting 成功:" + this.configs);
			return true;
		} catch (Exception e) {
			Log.w(Setting.class.getSimpleName(), "loadConfigsSetting 失败" ,e);
		}
		return false;
	}
	
	private BufferedReader getNewBufferedReader(String fileName) throws Exception {
		File file = new File( FileManager.getFileManager(ctx).getFilePath() +"/" + Setting.SETTING_PATH + "/" + fileName);
		BufferedReader isr = null;
		if ( file.exists() ) {//配置文件存在
			isr = new BufferedReader (new InputStreamReader( new FileInputStream( file ),"UTF-8") );
		} else {
			return null;
		}
		return isr;
	}
	
	public String getSetingFileRootPath() {
		return FileManager.getFileManager(ctx).getFilePath() +"/" + Setting.SETTING_PATH + "/" ;
	}
	
	private BufferedReader getDefaultBufferedReader(String fileName) throws Exception {
		return  new BufferedReader (new InputStreamReader( ctx.getAssets().open( Setting.SETTING_PATH + "/" + fileName ),"UTF-8") );
		
	}
	
	private void loadConfigServersSetting() {
		Queue<ConfigServer> tempconfigServers = new LinkedList<ConfigServer>();
		String versionLine = "versionLine";
		try {
			String line =null;
			
			BufferedReader isr = getNewBufferedReader(Setting.SETTING_CONFIGSERVERS_FILENAME);
			if ( isr == null ) {
				isr = this.getDefaultBufferedReader( Setting.SETTING_CONFIGSERVERS_FILENAME );
				versionLine = isr.readLine();
			} else {
				versionLine = isr.readLine();
				if ( versionLine == null  || versionLine.indexOf( Setting.SETTING_START ) < 0) {
					isr = this.getDefaultBufferedReader( Setting.SETTING_CONFIGSERVERS_FILENAME );
					versionLine = isr.readLine();
				}
			}
			
			if ( this.configServers != null && this.configServers.first.equals( versionLine )  ) {
				return;
			}
			
			while (  (line=isr.readLine()) != null ) {
				String[] ss = line.split("\\t");
				if ( ss.length >= 2) {
					tempconfigServers.add( new ConfigServer(ss[0],ss[1]) );
				}
			}
			this.configServers = new Pair<String ,Queue<ConfigServer>>(versionLine,tempconfigServers);
			Log.i(Setting.class.getSimpleName(), "loadConfigServersSetting 成功:" + this.configServers);
		} catch (Exception e) {
			tempconfigServers.add( Setting.DEFAULT_UPDATE_Server );
			this.configServers = new Pair<String ,Queue<ConfigServer>>(versionLine, tempconfigServers );
			Log.w(Setting.class.getSimpleName(), "loadConfigServersSetting 失败" ,e);
		}
	}
	
	private void loadURLs() {
		String versionLine = "versionLine";
		Map<String,URLInfo> tchinaURLs = new TreeMap<String,URLInfo>();//大陆网址
		Map<String,URLInfo> thongkongURLs = new TreeMap<String,URLInfo>();//香港网址
		Map<String,URLInfo> ttaiwanURLs = new TreeMap<String,URLInfo>();//台湾网址
		Map<String,URLInfo> thaiwaiURLs = new TreeMap<String,URLInfo>();//海外
		Map<String,URLInfo> tothersURLs = new TreeMap<String,URLInfo>();//其他
		try {
			String line =null;
			BufferedReader isr = getNewBufferedReader(Setting.SETTING_URLS_FILENAME);
			if ( isr == null ) {
				isr = this.getDefaultBufferedReader( Setting.SETTING_URLS_FILENAME );
				versionLine = isr.readLine();
			} else {
				versionLine = isr.readLine();
				if ( versionLine == null  || versionLine.indexOf( Setting.SETTING_START ) < 0) {
					isr = this.getDefaultBufferedReader( Setting.SETTING_URLS_FILENAME );
					versionLine = isr.readLine();
				}
			}
			
			if ( this.chinaURLs != null && this.chinaURLs.first.equalsIgnoreCase( versionLine ) 
				&& this.taiwanURLs != null && this.taiwanURLs.first.equalsIgnoreCase( versionLine )
				&& this.hongkongURLs != null && this.hongkongURLs.first.equalsIgnoreCase( versionLine )
				&& this.haiwaiURLs != null && this.haiwaiURLs.first.equalsIgnoreCase( versionLine )
				&& this.othersURLs != null && this.othersURLs.first.equalsIgnoreCase( versionLine )
				) {
				return;
			}
			
			while (  (line=isr.readLine()) != null ) {
				
				URLInfo tURLInfo = new URLInfo();
				//类型  url   title desc
				String[] ss = line.split("\\t");
				if ( ss.length >= 4) {
					tURLInfo.setType(ss[0]);
					tURLInfo.setUrl(ss[1]);
					tURLInfo.setOrder( ss[2] );
					tURLInfo.setTitle( ss[3] );
					if ( ss.length >= 5) {
						tURLInfo.setDes( ss[4] );
					}
					
					if ( tURLInfo.isChina() ) {
						tchinaURLs.put( tURLInfo.getUrl() , tURLInfo);
					} else if( tURLInfo.isHongKong() ) {
						thongkongURLs.put( tURLInfo.getUrl() , tURLInfo);
					} else if ( tURLInfo.isTaiwan() ) {
						ttaiwanURLs.put( tURLInfo.getUrl() , tURLInfo);
					} else if ( tURLInfo.isHaiwai() ) {
						thaiwaiURLs.put( tURLInfo.getUrl() , tURLInfo);
					} else if ( tURLInfo.isOthers() ) {
						tothersURLs.put( tURLInfo.getUrl() , tURLInfo);
					}
						
				}
			}
			Log.i(Setting.class.getSimpleName(), "loadURLs 成功:"+ thongkongURLs);
		} catch (Exception e) {
			Log.w(Setting.class.getSimpleName(), "loadURLs 失败" ,e);
		}
		this.chinaURLs = new Pair<String, Map<String,URLInfo>>(versionLine, tchinaURLs);
		this.hongkongURLs =  new Pair<String, Map<String,URLInfo>>(versionLine,thongkongURLs);
		this.taiwanURLs =  new Pair<String, Map<String,URLInfo>>(versionLine,ttaiwanURLs);
		this.haiwaiURLs =  new Pair<String, Map<String,URLInfo>>(versionLine,thaiwaiURLs);
		this.othersURLs =  new Pair<String, Map<String,URLInfo>>(versionLine,tothersURLs);
	}
	
	/**
	 * 得到当前的首个配置服务器，并根据文件名返回更新配置的全地址
	 * @param fileName
	 * @return
	 */
	private String getFirstConfigServer(String fileName) {
		if ( this.configServers != null && this.configServers.second != null
				&& this.configServers.second.peek() != null) {
			return this.configServers.second.peek().getConfigUrl( fileName);
		} 
		
		return Setting.DEFAULT_UPDATE_Server.getConfigUrl( fileName );
		
	}
	
	public ConfigServer getConfigServer() {
		if ( this.getConfigServers() != null && this.getConfigServers().second != null
				&& this.getConfigServers().second.peek() != null) {
			return this.getConfigServers().second.peek();
		} 
		
		return Setting.DEFAULT_UPDATE_Server;
	}
	
	/**
	 * 把第二个返回，并把第一个放队列后面
	 * @return
	 */
	private String getSecondConfigServer(String fileName) {
		if ( this.configServers != null && this.configServers.second != null
				&& this.configServers.second.peek() != null) {
			ConfigServer server = this.configServers.second.poll();// 
			this.configServers.second.offer( server);
			
			return this.configServers.second.peek().getConfigUrl(fileName);
		} else {
			return Setting.DEFAULT_UPDATE_Server.getConfigUrl( fileName );
		}
	}

	
//	public String getIndexURL() {
//		File indexFile = new File( FileManager.getFileManager(ctx).getFilePath() +"/" + Setting.SETTING_PATH + "/" + Setting.SETTING_INDEX_FILENAME);
//		String url =DEFAULT_INDEX_URL ;
//		try {
//			if ( indexFile.exists() ) {//配置文件存在
//				url = "file://" + indexFile;
//			} else {//默认asset下配置
//				url = DEFAULT_INDEX_URL;
//			}
//			return url;
//		} catch (Exception e) {
//			Log.w(Setting.class.getSimpleName(), "getIndexURL 失败" ,e);
//		} 
//		
//		Log.d(Setting.class.getSimpleName(), "getIndexURL return:" + url);
//		return url;
//	}
	

	
	private boolean updateConfigsSetting() {
		if(  !this.updateTextSettingFile(Setting.SETTING_CONFIGS_FILENAME, this.getFirstConfigServer(Setting.SETTING_CONFIGS_FILENAME + "?in=" + this.isFirstTimeUpdateConfig +"&av=" + this.getAppVersion()  + "&i=" + this.userId + "&lt=" + this.loginTimes) ) ) {
			 return this.updateTextSettingFile(Setting.SETTING_CONFIGS_FILENAME, this.getSecondConfigServer(Setting.SETTING_CONFIGS_FILENAME + "?in=" + this.isFirstTimeUpdateConfig +"&av=" + this.getAppVersion()  + "&i=" + this.userId + "&lt=" + this.loginTimes ) ); 
		} else {
			return true;
		}
	}
	
	public void updateSetting() {
		if( this.updateConfigsSetting() ) {
			this.isFirstTimeUpdateConfig = false;
			this.modified = true;
		}
		this.loadConfigsSetting();//不管更新配置文件是否成功，本地的还是要做
		Log.d(Setting.class.getSimpleName(), "updateSetting ok configs:" + this.configs);
		if (this.configs != null && this.configs.second != null ) {
			Collection<UpdateFileInfo> updateFileInfos = this.configs.second.values();
			for( UpdateFileInfo updateFileInfo :updateFileInfos ) {
				if ( updateFileInfo.isTimeLimit() ) {
					if( this.configs.second.size() >= 100 ) {
						//超出更新限制，而且总数目太大，删除掉
						this.configs.second.remove( updateFileInfo.getFileName() );
					}
				} else {
					if ( updateFileInfo.isText() ) {
						if ( this.updateTextSettingFile(updateFileInfo.getFileName(), updateFileInfo.getUpdateURL() ) ) {
							updateFileInfo.setUpdated(true);
						}
					} else if ( updateFileInfo.isBin() ) {
						if ( this.updateBinSettingFile(updateFileInfo.getFileName(), updateFileInfo.getUpdateURL() ) ) {
							updateFileInfo.setUpdated(true);
						}
					}
					updateFileInfo.setUpdateRetryTimes( updateFileInfo.getUpdateRetryTimes() + 1 );
				}
				this.modified =true;
			}
		}
	}
	

	/**
	 * 更新文本配置文件文件
	 */
	private boolean updateTextSettingFile(String settingFileName, String settingFileUpdateURL) {
        try {
        	Log.d(Setting.class.getSimpleName(), "updateTextSettingFile start:" + settingFileUpdateURL); 
        	HttpClient hc = new DefaultHttpClient();  
    		
            HttpGet hg = new HttpGet( settingFileUpdateURL ); 
            hg.addHeader("User-Agent", "Opera/9.80 (Windows NT 6.1; U; Edition IBIS; zh-cn) Presto/2.10.229 Version/11.60");
        	//检查本地文件
        	File settingPath = new File( FileManager.getFileManager(ctx).getFilePath() +"/" + Setting.SETTING_PATH + "/");
			File settingFile =  new File( settingPath.getAbsoluteFile() + "//" + settingFileName );
			String oldFirstLine = "";
			if ( !settingPath.exists() ) {
				settingPath.mkdirs();
			} else if ( settingFile.exists() ) {
				try {
					oldFirstLine = new BufferedReader (new InputStreamReader( new FileInputStream(settingFile),"UTF-8") ).readLine();
				} catch (IOException e) {
					 Log.w(Setting.class.getSimpleName(), "updateTextSettingFile read file=" + settingFileName,e );
				}
			}
        	
        	
            HttpResponse hr = hc.execute(hg); 
            BufferedReader isr = new BufferedReader (new InputStreamReader( hr.getEntity().getContent() ,"UTF-8") );
            String htmlString = "";
            String line = null;
            //读取判断第一行
            line = isr.readLine();
            Log.d(Setting.class.getSimpleName(), "updateTextSettingFile "+ settingFileName + " oldFirstLine=" + oldFirstLine + ";newline=" + line.trim() + ";" + line.trim().indexOf(Setting.SETTING_START) );
            if ( line != null && line.trim().indexOf(Setting.SETTING_START) >= 0
            		&& !line.equals(oldFirstLine) ) {
            	htmlString = htmlString + line + "\n";
            	//合法的文件
	            while ( (line=isr.readLine()) != null  ) {
	            	htmlString = htmlString + line + "\n";
	            	//Log.d(Setting.class.getSimpleName(), "updateSetting readline:" + line );
	            }
	            BufferedWriter bw  = new BufferedWriter (new OutputStreamWriter( new FileOutputStream(settingFile),"UTF-8") );
	            bw.write(htmlString);
	            bw.close();//记得关闭写缓存，不然文件没数据
	            //配置文件更新成功，更新配置
	           // Log.d(Setting.class.getSimpleName(), "updateTextSettingFile:" + settingFileName +" 得到更新的内容:" + htmlString); 
            }
            return true;
        } catch (Exception e) {  
        	Log.e(Setting.class.getSimpleName(), "updateTextSettingFile error :" + e.getMessage(),e);
        }  
        return false;
	}
	
	/**
	 * 更新二进制文件
	 * @param settingFileName
	 * @param settingFileUpdateURL
	 * @return
	 */
	private boolean updateBinSettingFile(String settingFileName, String settingFileUpdateURL) {
		
        try {
        	Log.d(Setting.class.getSimpleName(), "updateBinSettingFile start:" + settingFileUpdateURL); 
        	HttpClient hc = new DefaultHttpClient();  
    		
            HttpGet hg = new HttpGet( settingFileUpdateURL ); 
            hg.addHeader("User-Agent", "Opera/9.80 (Windows NT 6.1; U; Edition IBIS; zh-cn) Presto/2.10.229 Version/11.60");
        	//检查本地文件
        	File settingPath = new File( FileManager.getFileManager(ctx).getFilePath() +"/" + Setting.SETTING_PATH + "/");
			File settingFile =  new File( settingPath.getAbsoluteFile() + "//" + settingFileName );
			File settingTempFile =  new File( settingPath.getAbsoluteFile() + "//" + settingFileName + ".temp" );
			if ( !settingPath.exists() ) {
				settingPath.mkdirs();
			} 
			
            HttpResponse hr = hc.execute(hg); 
            InputStream is =  hr.getEntity().getContent();
            
			FileOutputStream fos = new FileOutputStream(settingTempFile); 
			byte[] buffer = new byte[1024];
			int len = 0;
			while ((len = is.read(buffer)) != -1) {
				fos.write(buffer, 0, len);
			}
			fos.close();
			is.close();
            
			FileHelper.copyFileTo(settingTempFile,settingFile);
			FileHelper.delFile( settingTempFile );
			
			Log.d(Setting.class.getSimpleName(), "updateBinSettingFile ok :" + settingFileUpdateURL);
        } catch (Exception e) {  
        	Log.e(Setting.class.getSimpleName(), "updateBinSettingFile error :" + e.getMessage(),e);
        }  
        return false;
	}
	
	/**
	 * 是否设置使用智能代理，默认是
	 * @return
	 */
	public boolean isUseProxy() {
		//读取配置并返回
		return PreferenceManager.getDefaultSharedPreferences(this.ctx).getBoolean(Setting.USE_PROXY_KEY, true);
	}
	
	public void setUseProxy(boolean useProxy) {
		//保存到配置里面
		PreferenceManager.getDefaultSharedPreferences(this.ctx).edit().putBoolean(Setting.USE_PROXY_KEY, useProxy).commit();
	}
	
	public String getFontSize() {
		return PreferenceManager.getDefaultSharedPreferences(this.ctx).getString(Setting.FONT_KEY, Setting.FONT_NORMAL);
	}
	
	private  byte[] object2Bytes() {
		try {
			ByteArrayOutputStream b = new ByteArrayOutputStream();
			ObjectOutputStream out = new ObjectOutputStream(b);
			out.writeObject(this);
			byte[] ob =  b.toByteArray();
			if ( ob == null || ob.length == 0 ) {
				return null;
			}
			//Log.d(this.getClass().getSimpleName(), "object2Bytes lentgh:" + ob.length);
			return ob;
		} catch (IOException e) {
			Log.e(this.getClass().getSimpleName(), "object2Bytes",e);
			return null;
		}
	}
	
	public static Setting bytes2Object(byte[] bts) {
		if ( bts == null || bts.length == 0) {
			return null;
		}
		try {
			ByteArrayInputStream i = new ByteArrayInputStream(bts);
			ObjectInputStream in = new ObjectInputStream(i);
			return (Setting)in.readObject();
		} catch (Exception e) {
			return null;
		}
	}
	
//	public Map<String, URLInfo> getUrls() {
//		if( this.urls == null ) {
//			this.loadURLsSetting();
//		}
//		if( this.urls == null ) {
//			return new HashMap<String, URLInfo>();
//		}
//		return urls;
//	}

	public void saveInstanceState(Bundle outState) {
		outState.putByteArray("Setting", this.object2Bytes());
	}
	
	public static Setting restoreInstanceState(Bundle inState, Context ctx) {
		byte[] bs = (byte[])inState.get("Setting");
		if ( bs != null ) {
			Setting setting = Setting.bytes2Object(bs);
			if ( setting != null ) {
				setting.ctx = ctx;
			}
			return setting;
		}
		return null;
	}

	public VHostInfo getVhostsByHost(String fullHost) {
		if ( null == vhosts ) {
			this.loadVhostsSetting();
		}
		if( fullHost == null ) {
			return null;
		}
		String shortHost = fullHost;
		String[] s = shortHost.split("\\.");
		if (  s.length >= 2 &&  "com.net.org.me".indexOf(s[s.length-1].toLowerCase() ) >=0 ) {
			shortHost =  s[s.length-2] + "." + s[s.length-1];
		} else if( s.length >= 4) {
			shortHost = s[s.length-3] + "." + s[s.length-2] + "." + s[s.length-1];
		} 
		
		VHostInfo vHostInfo = this.vhosts.get(shortHost);
		if ( vHostInfo == null ) {
			vHostInfo = this.vhosts.get(fullHost);
		}

		return vHostInfo;
	}
	
	/**
	 * 更新点击次数
	 */
//	public void updateURLClick(String url) {
//		//统计,增加一次点击
//		if ( this.urls != null ) {
//			Log.d(HKWebViewClient.class.getSimpleName(),"urlInfo 1:" + this.urls);
//			URLInfo urlInfo  = this.urls.get( url) ;
//			if ( urlInfo != null ) {
//				urlInfo.addClickCount();
//				this.modified = true;
//				Log.d(HKWebViewClient.class.getSimpleName(),"urlInfo:" + urlInfo);
//			}
//		}
//	}
	
	
	


	public long getLastRunTime() {
		return startTime;
	}

	public boolean isModified() {
		return modified;
	}

	public void setModified(boolean modified) {
		this.modified = modified;
	}


	public Map<String, UpdateFileInfo> getConfigs() {
		return configs.second;
	}

	public long getStartTime() {
		return startTime;
	}

	public void setStartTime(long startTime) {
		this.startTime = startTime;
	}

	public boolean isFirstTimeUpdateConfig() {
		return isFirstTimeUpdateConfig;
	}

	public void setFirstTimeUpdateConfig(boolean isFirstTimeUpdateConfig) {
		this.isFirstTimeUpdateConfig = isFirstTimeUpdateConfig;
	}

	public Map<String, URLInfo> getChinaURLs() {
		if ( null == this.chinaURLs ) {
			this.loadURLs();
		}
		return chinaURLs.second;
	}


	public Map<String, URLInfo> getHongkongURLs() {
		if ( null == this.hongkongURLs ) {
			this.loadURLs();
		}
		return hongkongURLs.second;
	}

	public Map<String, URLInfo> getTaiwanURLs() {
		if ( null == this.taiwanURLs ) {
			this.loadURLs();
		}
		return taiwanURLs.second;
	}

	public void setCtx(Context ctx) {
		this.ctx = ctx;
	}

	public void setVhosts(Map<String, VHostInfo> vhosts) {
		this.vhosts = vhosts;
	}

	public static Setting getSetting() {
		return setting;
	}

	public static void setSetting(Setting setting) {
		Setting.setting = setting;
	}

	public Pair<String, Queue<ConfigServer>> getConfigServers() {
		if( null == this.configServers ) {
			this.loadConfigServersSetting();
		}
		return configServers;
	}

	public void setConfigServers(Pair<String, Queue<ConfigServer>> configServers) {
		this.configServers = configServers;
	}

	public void setConfigs(Pair<String, Map<String, UpdateFileInfo>> configs) {
		this.configs = configs;
	}

	public void setChinaURLs(Pair<String, Map<String, URLInfo>> chinaURLs) {
		this.chinaURLs = chinaURLs;
	}

	public void setHongkongURLs(Pair<String, Map<String, URLInfo>> hongkongURLs) {
		this.hongkongURLs = hongkongURLs;
	}

	public void setTaiwanURLs(Pair<String, Map<String, URLInfo>> taiwanURLs) {
		this.taiwanURLs = taiwanURLs;
	}
	
	
	/** 
	 * 返回当前程序版本名 
	 */  
	public String getAppVersionName() {  
	    String versionName = "";  
	    try {  
	        // ---get the package info---  
	        PackageManager pm = ctx.getPackageManager();  
	        PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), 0);  
	        versionName = pi.versionName;  
	        if (versionName == null || versionName.length() <= 0) {  
	            return "";  
	        }  
	    } catch (Exception e) {  
	        Log.e("VersionInfo", "Exception", e);  
	    }  
	    return versionName;  
	} 
	
	/** 
	 * 返回当前程序版本名
	 */  
	public int getAppVersion() {  
	    int versionCode = 0;  
	    try {  
	        // ---get the package info---  
	        PackageManager pm = this.ctx.getPackageManager();  
	        PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), 0);  
	        versionCode = pi.versionCode;
	    } catch (Exception e) {  
	        Log.e("VersionInfo", "Exception", e);  
	    }  
	    return versionCode;  
	}

	public boolean isNeedUpdateVersion() {
		if( this.updateName == null || this.updateName.equals("") ) {
			return false;
		}
		try {
			//name url updatetype desc
			int newVersion = Integer.parseInt( updateName.split("-")[2].split("\\.")[0] );
			if( newVersion > this.getAppVersion() ) {
				return true;
			}
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		
		this.updateName = null;
		this.setModified( true);
		return false;
	}



	public String getUpdateVersionUrl() {
		return updateVersionUrl;
	}

	public void setUpdateVersionUrl(String updateVersionUrl) {
		this.updateVersionUrl = updateVersionUrl;
	}

	public String getUpdateName() {
		return updateName;
	}

	public void setUpdateName(String updateName) {
		this.updateName = updateName;
	}

	public String getUpdateType() {
		return updateType;
	}

	public void setUpdateType(String updateType) {
		this.updateType = updateType;
	}

	public String getUpdateDesc() {
		return updateDesc;
	}

	public void setUpdateDesc(String updateDesc) {
		this.updateDesc = updateDesc;
	}

	public Map<String, URLInfo> getHaiwaiURLs() {
		if ( null == this.haiwaiURLs ) {
			this.loadURLs();
		}
		return this.haiwaiURLs.second;
	}

	public void setHaiwaiURLs(Pair<String, Map<String, URLInfo>> haiwaiURLs) {
		this.haiwaiURLs = haiwaiURLs;
	}

	public Map<String, URLInfo> getOthersURLs() {
		if ( null == this.othersURLs ) {
			this.loadURLs();
		}
		return othersURLs.second;
	}

	public void setOthersURLs(Pair<String, Map<String, URLInfo>> othersURLs) {
		this.othersURLs = othersURLs;
	}

//	public int getLocalPort() {
//		SharedPreferences  info =ctx.getSharedPreferences("Socket5Setting",0); 
//        
//        //proxy = info.getString("proxyHost","192.168.2.104"); 
//       // port = info.getInt("proxyPort",1080);
//        username=info.getString("username", "first");
//        password=info.getString("password", "first");
//        localPort=info.getInt("localPort", 8080);
//		return localPort;
//	}
//
//	public void setLocalPort(int localPort) {
//		Editor info = ctx.getSharedPreferences("Socket5Setting", 0).edit();  
//		   //info.putString("proxyHost",proxy);  
//		   //info.putInt("proxyPort", port);
//		   info.putString("username",username);
//		   info.putString("password",password);
//		   info.putInt("localPort", localPort);
//		this.localPort = localPort;
//	}
//
//	public String getProxyHost() {
//		return proxyHost;
//	}
//
//	public void setProxyHost(String proxyHost) {
//		this.proxyHost = proxyHost;
//	}
//
//	public int getProxyPort() {
//		return proxyPort;
//	}
//
//	public void setProxyPort(int proxyPort) {
//		this.proxyPort = proxyPort;
//	}
//
//	public String getUsername() {
//		return username;
//	}
//
//	public void setUsername(String username) {
//		this.username = username;
//	}
//
//	public String getPassword() {
//		return password;
//	}
//
//	public void setPassword(String password) {
//		this.password = password;
//	}

	public boolean isRemaindedUpdate() {
		return isRemaindedUpdate;
	}

	public void setRemaindedUpdate(boolean isRemaindedUpdate) {
		this.isRemaindedUpdate = isRemaindedUpdate;
	}

	public int getLoginTimes() {
		return loginTimes;
	}

	public void setLoginTimes(int loginTimes) {
		this.loginTimes = loginTimes;
		this.modified = true;
	}

	public long getUserId() {
		return userId;
	} 
	
	
}
